package com.taoyun.service.impl;

import com.obs.services.ObsClient;
import com.obs.services.exception.ObsException;
import com.taoyun.config.ObsConfig;
import com.taoyun.mapper.*;
import com.taoyun.pojo.dto.DeleteDTO;
import com.taoyun.pojo.entity.*;
import com.taoyun.pojo.vo.RecycleFileVO;
import com.taoyun.service.IFileService;
import com.taoyun.service.IObsService;
import com.taoyun.utils.Response;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
@Transactional(rollbackFor = Exception.class)
public class FileServiceImpl implements IFileService{
    @Autowired
    private FileMapper fileMapper;
    @Autowired
    private IObsService obsService;
    @Autowired
    private MpFileMapper mpFileMapper;
    @Autowired
    private USendFMapper uSendFMapper;
    @Autowired
    private ObsConfig cfg;
    @Autowired
    private GroupMapper groupMapper;
    @Autowired
    private FileBelongGroupMapper fileBelongGroupMapper;
    @Autowired
    private UserMapper userMapper;

    public ObsClient getObsClient() {
        return new ObsClient(cfg.getAccessKeyId(), cfg.getSecretAccessKey(), cfg.getEndpoint());
    }


    @Override
    public void putRecycleBin(Integer userId, List<Integer> fileIds) {
        fileIds.forEach(fileId->fileMapper.putRecycleBin(userId,fileId,String.valueOf(1)));
    }

    @Override
    public String restoreRecycleBin(List<Integer> fileIds) {
        StringBuilder error = new StringBuilder("以下文件未恢复：");
        boolean checkError = false;
        for (Integer fileId : fileIds) {
            // 记录修改失败的fileId
            if(1>fileMapper.putRecycleBin(null,fileId,String.valueOf(0))){
                error.append(fileId);
                error.append(" ");
                checkError = true;
            }
        }
        if(checkError){
            error.append("!");
        }
        return error.toString();
    }

    @Override
    public void deleteFromRecycleBin(List<Integer> fileIds) {
        // 遍历文件，删除obs，删除数据库，释放用户空间
        for (Integer fileId : fileIds) {
            DeleteDTO deleteDTO = fileMapper.findObjectNamesById(fileId);
            String cutObjectName = cutPath(deleteDTO.getObjectName());
            fileMapper.reduce_objectData(cutObjectName,deleteDTO.getFileSize());
            fileMapper.deleteFileData(fileId);
            fileMapper.deleteFileData2(fileId);
            fileMapper.deleteFileData3(fileId);
            obsService.deleteObject(deleteDTO.getPathName());
        }
    }

    /**
     *  切割字符串： aaa/bbb/ccc/ -> aaa/bbb/
     * @param path path
     * @return
     */
    public String cutPath(String path){
        // aaa/bbb/ccc/ -> aaa,bbb,ccc
        String[] splits = path.split("/");
        if(splits.length>2){
            // aaa+"/"+bbb+"/" = aaa/bbb/
            return splits[0]+"/"+splits[1]+"/";
        }
        // 返回原串
        return path;
    }

    @Override
    public List<RecycleFileVO> getRecycleBin(Integer userId) {
        return fileMapper.getRecycleBin(userId);
    }


    @Override
    public boolean renameObjects(String objectName, String newObjectName) {
        // 检测是否有重名
        if(ifFileExist(newObjectName)){
            return false;
        }
        obsService.renameObjects(objectName, newObjectName);
        // 取路径后把最后一个'/'后的字符串作为文件名
        String reg = "([^<>/\\\\\\|:\"\"\\*\\?]+\\.\\w+$)";
        Matcher m = Pattern.compile(reg).matcher(newObjectName); //uri为需要匹配的路径
        String filename =  null;
        if (m.find()) {
            filename = m.group(1);
        }
        String filePath = newObjectName.substring(0,newObjectName.length()-filename.length());
        fileMapper.updateObjectName(objectName, newObjectName,filename,filePath);
        return true;
    }

    @Override
    public String getObjectLink( long expireSeconds, String objectName) {
        return obsService.getObjectLink(expireSeconds, objectName);
    }

    @Override
    public void createFileSystem(String bucketName) throws IOException {
        obsService.createFileSystem(bucketName);
    }

    //根据当前路径，模糊查询文件
    @Override
    public List<File> SearchFile_ByName(String now_path, String file_name) {
        List<File> all_file = fileMapper.SearchFile_ByName(now_path,file_name);
        //List<File> result = new ArrayList<>();
        //for(File a: all_file){
        //    String [] arr = a.getPathName().split("/");
        //    int logo = Integer.parseInt(a.getDeleteLogo());
        //    if(arr[arr.length-1].indexOf(file_name) != -1 && logo == 0){
         //       result.add(a);
        //    }
       // }
        return all_file;
    }

    //根据当前路径名，返回当前路径的文件
    @Override
    public List<File> ShowFile(String now_path){
        List<File> all_file = fileMapper.ShowFile(now_path);
        return all_file;
    }

    //根据根目录名，返回Object类，此处计算用户所用空间大小
    @Override
    public  ObjectSize get_user_data(String ObjectName) {
        return fileMapper.get_user_data(ObjectName);
    }

    //
    @Override
    public ObjectSize objectSize(String ObjectName) {
        return fileMapper.objectSize(ObjectName);
    }


    //通过对象名和上传文件的大小，更新ObjectSize表的used_dataSize
    @Override
    public int add_objectData(String ObjectName){
        return fileMapper.add_objectData(ObjectName);
    }

    //通过对象名和删除文件的大小，更新ObjectSize表的used_dataSize
    @Override
    public int reduce_objectData(String ObjectName,long size){
        return fileMapper.reduce_objectData(ObjectName,size);
    }

    //创建用户时,在ObjectSize表新建行
    @Override
    public int insert_ObjectSize(String ObjectName,long dataSize){
        return fileMapper.insert_ObjectSize(ObjectName,dataSize);
    }

    //删除用户时,在ObjectSize表删除行
    @Override
    public int delete_ObjectSize(String ObjectName){
        return fileMapper.delete_ObjectSize(ObjectName);
    }


    //判断file表文件存在与否
    @Override
    public  boolean ifFileExist(String path_Name) {
        if(fileMapper.countFile(path_Name)>0){
            return true;
        }else
        {
            return false;
        }
    }

    //判断USendF表中关系是否存在
    @Override
    public boolean ifUSendFExist(int user_Id, int file_Id) {
        if(fileMapper.countUSendF(user_Id,file_Id)>0){
            return true;
        }else
        {
            return false;
        }
    }

    @Override
    public boolean ifFbelongGExist(int F_Id, int GroupId) {
        if(fileMapper.countFbelongF(F_Id,GroupId)>0){
            return true;
        }else
        {
            return false;
        }
    }


    @Override
    public boolean ifObjectNameExist(String ObjectName) {
        if(fileMapper.ifObjectNameExist(ObjectName)>0){
            return true;
        }else
        {
            return false;
        }
    }


    //查询同名文件
    @Override
    public int selectFileIdByPathName(String path_Name) {
        return fileMapper.selectFileIdByPathName(path_Name);
    }

    //上传文件到obs，更新数据库操作
    @Override
    public File handleUploadFile(MultipartFile file, String file_Path, String author, int user_Id) {

        //obs对象名
        String[] arrays = file_Path.split("/");
        String obsObjectName=arrays[0];
        //上传文件整体路径文件名
        String file_Names = file.getOriginalFilename();
        if(file_Names.length()>255){
            throw new RuntimeException("文件名过长！");
        }

        //文件完整路径加文件名
        String path_Name = file_Path + file_Names;
        //单独文件名
        String[] a =path_Name.split("/");
        String file_Name=a[a.length-1];
        //obs路径
        String path = "";
        for(int i = 0;i < a.length-1;i++) path += a[i] + "/";

        //设置用于更新用户使用空间大小的参数
        String pathofsize = a[0]+'/'+a[1]+'/';

        //上传文件作者
        //author
        //共享路径
        String sharePath = path_Name;

        //文件创建时间
        SimpleDateFormat dateFormat= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date nowTime = Timestamp.valueOf(dateFormat.format(new Date()));
        //文件类型
        String[] fileTypes = file_Name.split("\\.");
        String fileType=fileTypes[fileTypes.length-1];
        //修改时间-LMTime-暂不添加

        //文件大小
        int fileSize=(int)file.getSize();

        //上传时判断数据库file是否存在同名条目
        boolean result = ifFileExist(path_Name);

        System.out.println("---------"+path_Name);
        File fn;

        if (result){
            //若存在相同文件路径名，则文件重复，数据库表更新
            //创建时间为空，nowTime 为 修改时间
            int file_Id = selectFileIdByPathName(path_Name);
            fn = new File(file_Id, obsObjectName, path, file_Name, path_Name, author, sharePath, "0", null, fileType, nowTime, fileSize);
            mpFileMapper.updateById(fn);
        }else {
            //将数据注入到文件类对象,此时是新插入
            //创建时间与修改时间都为 nowTime
            fn = new File(null, obsObjectName, path, file_Name, path_Name, author, sharePath, "0", nowTime, fileType, nowTime, fileSize);
            mpFileMapper.insert(fn);
        }

        //上传文件后更新
        add_objectData(pathofsize);

        //判断是否是个人文件或者群组文件
        int file_Id = fn.getFileId();
        String[] array2 = file_Path.split("/");
        System.out.println(array2[0]);

        if("user".equals(array2[0])){
            //获取User_Id,File_Id,SentTime插入U_sent_F表
            U_send_F u_send_f = new U_send_F(user_Id,file_Id, nowTime);
            boolean result2=ifUSendFExist(user_Id,file_Id);
            //上传时判断数据库file是否存在同名条目
            if(result2){
                //uSendFMapper.updateById(u_send_f); 此语句会造成主键冲突
                fileMapper.updateUSendF(user_Id,file_Id,nowTime);
            }else {
                uSendFMapper.insert(u_send_f);
            }
        }

        if("groups".equals(array2[0]))
        {
            int groupId = Integer.parseInt(array2[1]);
            System.out.println(groupId);
            insertF_belong_G(file_Id, groupId,user_Id);
        }
        System.out.println("成功");
        return fn;
    }

    @Override
    public void insertFileNullFolder(MultipartFile file, String file_Path, String author) {

        //上传文件整体路径文件名
        String file_Names = file.getOriginalFilename();
        if(file_Names.length()>255){
            throw new RuntimeException("文件名过长！");
        }
        //文件完整路径加文件名
        String FullPath = file_Path + file_Names;
        //处理
        String[] arrays = file_Path.split("/");
        String obsObjectName=arrays[0];
        //单独文件夹名
        String[] a =FullPath.split("/");
        String file_Name=a[a.length-2];
        //Path
        String path = "";
        for(int i = 0;i < a.length-2;i++) path += a[i] + "/";
        String path_Name = path+file_Name;
        String sharePath = path_Name;
        //文件夹创建时间
        SimpleDateFormat dateFormat= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date nowTime = Timestamp.valueOf(dateFormat.format(new Date()));
        //文件类型
        String fileType="folder";
        //上传时判断数据库file是否存在同名条目
        boolean result = ifFileExist(path_Name);
        File fn;

        if (result){
            //若存在相同文件路径名，则文件重复，数据库表更新
            //创建时间为空，nowTime 为 修改时间
            int file_Id = selectFileIdByPathName(path_Name);
            fn = new File(file_Id, obsObjectName, path, file_Name, path_Name, author, sharePath, "0", null, fileType, nowTime, 0);
            mpFileMapper.updateById(fn);
        }else {
            //将数据注入到文件类对象,此时是新插入
            //创建时间与修改时间都为 nowTime
            fn = new File(null, obsObjectName, path, file_Name, path_Name, author, sharePath, "0", nowTime, fileType, nowTime, 0);
            mpFileMapper.insert(fn);
        }

    }

    //上传文件更新F_belong_G表
    @Override
    public void insertF_belong_G(int fileId, int GroupId,int U_Id) {
        //获取G_id
        Integer G_id;
        try{
            G_id = groupMapper.SelectGroupByGroupId(GroupId,U_Id).getGId();
        } catch (Exception e) {
            throw new RuntimeException("无法找到该群组用户！");
        }
        FileBelongGroup adds = new FileBelongGroup(G_id,fileId,GroupId);
        boolean result3 = ifFbelongGExist(fileId,GroupId);
        if(result3) {
            return;
        }else{
            fileBelongGroupMapper.addFBelongG(adds);
        }
    }


    // 判断是否足够空间上传judge
    @Override
    public void judgeObjectSizeWhenUpload(MultipartFile file, String file_Path) {
        //obs对象名
        String[] arrays = file_Path.split("/");
        String obsObjectName = null;
        try {
            obsObjectName=arrays[0]+'/'+arrays[1]+'/';
            System.out.println(obsObjectName);
        } catch (Exception e) {
            throw new RuntimeException("不要直接上传文件到根目录，请创建子文件夹！");
        }

        //判断存储空间
        boolean result4 =ifObjectNameExist(obsObjectName);
        if(result4!=true) {
            throw new RuntimeException("存储空间未分配！");
        }
        //当前文件大小
        int fileSize=(int)file.getSize();
        //上传前对用户剩余的存储空间查询判断
        ObjectSize objectSize = get_user_data(obsObjectName);


        if(fileSize>objectSize.getDataSize()-objectSize.getUsedSize())
        {
            throw new RuntimeException("用户剩余云盘空间不足");
        }


    }



    //文件上传obs
    @Override
    public void uploadFile(MultipartFile file, String file_path) {
        //获取上传的文件名
        String file_Name = file.getOriginalFilename();
        InputStream inputStream = null;

        try {
            //将MultipartFile转换成文件流
            inputStream = file.getInputStream();
        } catch (IOException e1) {
            System.out.println("文件流大小超过上限，此处设定的单个上传大小为1000MB");
            e1.printStackTrace();
        }
        //创建obsClient实例
        ObsClient obsClient = this.getObsClient();
        String bucketName=cfg.getBucketName();
        //文件对象命名
        String objectName=file_path+file_Name;
        //System.out.println(file_Name);
        try {
            obsClient.putObject(bucketName, objectName,inputStream);
        } catch (ObsException e) {
            e.printStackTrace();
        }
    }




    @Override
    public Response downloadfile(String bucketName, String objectNames, String fileLocatePrefix) throws IOException {
        return obsService.downloadfile(bucketName, objectNames,fileLocatePrefix);
    }

    @Override
    public void downloadprogress(String bucketName,String objectName) throws IOException {
        obsService.downloadprogress(bucketName, objectName);
    }



    @Override
    public void showobjectName(String bucketName,String objectName) throws IOException {
        obsService.showobjectName(bucketName, objectName);
    }


    @Override
    public void moveObject(String sobjectName,String dobjectName) {
        if(obsService.moveObject(sobjectName,dobjectName).isEmpty()){
            System.out.println("error");
        } else{
            String reg = "([^<>/\\\\\\|:\"\"\\*\\?]+\\.\\w+$)";
            Matcher m = Pattern.compile(reg).matcher(dobjectName); //uri为需要匹配的路径
            String filename =  null;
            if (m.find()) {
                filename = m.group(1);
            }
            String filePath = dobjectName.substring(0,dobjectName.length()-filename.length());
            fileMapper.updateObjectName(sobjectName, dobjectName,filename,filePath);
        }
    }

    @Override
    public void copyObject(String sobjectName,String dobjectName){
        //obs对象名
        String[] filepaths = sobjectName.split("/");
        String[] dobjectPaths = dobjectName.split("/");
        String obsojectName=filepaths[0];
        //工号
        String userNumber = dobjectPaths[1];
        //文件名
        String file_Name = filepaths[filepaths.length-1];
        //obs路径
        String path=dobjectName.replace(file_Name, "");
        //文件路径
        String path_Name=dobjectName;
        //System.out.println(path_Name);
        //上传文件作者
        String author=filepaths[1];
        //共享路径
        String sharePath=path;
        //文件创建时间
        Date creatTime = new Date();
        SimpleDateFormat dateFormat= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //文件类型
        String[] fileTypes = file_Name.split("\\.");
        String fileType=fileTypes[fileTypes.length-1];
        //文件大小
        int fileSize = fileMapper.selectFileSizeByPathName(sobjectName);
        obsService.copyObject(sobjectName,dobjectName);
        File file = new File("user", path, file_Name, path_Name, author, sharePath, "0", creatTime, fileType, fileSize);
        fileMapper.insertFileReturnId(file);
        //插入U_send_F表
        User user = userMapper.SearchUserByNumber(userNumber);
        U_send_F u_send_f = new U_send_F(user.getUserId(),file.getFileId(), new Date());
        uSendFMapper.insert(u_send_f);
        //修改ObjectSize大小
        fileMapper.add_objectData("user/" + userNumber + "/");
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
    public void shareobject(String url,String dobject){
        int location=0;
        int lastIndex=0;
        int firstIndex = url.indexOf("/");//*第一个出现的索引位置
        while (firstIndex != -1){
            firstIndex = url.indexOf("/", firstIndex + 1);//*从这个索引往后开始第一个出现的位置
            location++;
            if(location==2){
                lastIndex=url.indexOf("?");
                url=url.substring(firstIndex+1,lastIndex);
            }
        }
        try {
            url = URLDecoder.decode(url, "utf-8");
        }
        catch (UnsupportedEncodingException e){

        }
        //obs对象名
        String[] filepaths = url.split("/");
        String[] sfilepaths = url.split("/");
        String[] dobjectPaths = dobject.split("/");
        String obsojectName=filepaths[0];
        //文件名
        String file_Name = filepaths[filepaths.length-1];
        //工号
        String userNumber = dobjectPaths[1];
        //obs路径
        String path=dobject;
        //文件路径
        String path_Name=dobject+file_Name;
        //System.out.println(path_Name);
        //上传文件作者
        String author = sfilepaths[1];
        //共享路径
        String sharePath=path;
        //文件创建时间
        Date creatTime = new Date();
//        SimpleDateFormat dateFormat= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //文件类型
        String[] fileTypes = file_Name.split("\\.");
        String fileType=fileTypes[fileTypes.length-1];
        //文件大小
        System.out.println(url);
        int fileSize = fileMapper.selectFileSizeByPathName(url);
        obsService.copyObject(url,path_Name);
        File file = new File("user", path, file_Name, path_Name, author, sharePath, "0", creatTime, fileType, fileSize);
        fileMapper.insertFileReturnId(file);
        //插入U_send_F表
        User user = userMapper.SearchUserByNumber(userNumber);
        U_send_F u_send_f = new U_send_F(user.getUserId(),file.getFileId(), new Date());
        uSendFMapper.insert(u_send_f);
        //修改ObjectSize大小
        fileMapper.add_objectData("user/" + userNumber + "/");
    }

    @Override
    public List<String> getDownloadLink(List<String> objectNames) {
        return obsService.getDownloadLink(objectNames);
    }
}
